package cn.iocoder.yudao.module.javainfo.service.financialflow;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.javainfo.controller.admin.financialflow.vo.*;
import cn.iocoder.yudao.module.javainfo.dal.dataobject.financialflow.FinancialFlowDO;
import cn.iocoder.yudao.module.javainfo.dal.dataobject.pet.PetDO;
import cn.iocoder.yudao.module.javainfo.dal.mysql.financialflow.FinancialFlowMapper;
import cn.iocoder.yudao.module.javainfo.enums.AmountTypeEnum;
import cn.iocoder.yudao.module.javainfo.service.pet.PetService;
import cn.iocoder.yudao.module.javainfo.service.user.JavaInfoUserService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.javainfo.enums.ErrorCodeConstants.FINANCIAL_BALANCE_NOT_ENOUGH;

/**
 * 资金流水 Service 实现类
 *
 * @author 爪哇国大BOSS
 */
@Service
@Validated
public class FinancialFlowServiceImpl implements FinancialFlowService {

    @Resource
    private FinancialFlowMapper financialFlowMapper;

    @Resource
    private JavaInfoUserService javaInfoUserService;

    @Resource
    private PetService petService;

    @Override
    public Long createFinancialFlow(FinancialFlowSaveReqVO createReqVO) {
        // 1. 获取用户最新的资金流水记录
        FinancialFlowDO latestFlow = financialFlowMapper.selectLatestByUserId(createReqVO.getUserId());
        Long previousBalance = latestFlow != null ? latestFlow.getBalanceAfter() : 0L;

        // 2. 根据交易类型计算变动后余额
        Long balanceAfter = calculateBalanceAfter(createReqVO, previousBalance);

        // 3. 设置计算后的余额
        createReqVO.setBalanceAfter(balanceAfter);

        // 设置订单号，由用户id+时间戳+交易类型组成
        createReqVO.setOrderNumber(createOrderNo(createReqVO.getUserId(), createReqVO.getAmountType()));

        // 4. 插入记录
        FinancialFlowDO financialFlow = BeanUtils.toBean(createReqVO, FinancialFlowDO.class);
        // 清空BaseDO中的字段，避免creator字段冲突
        financialFlow.clean();
        financialFlowMapper.insert(financialFlow);
        // todo 接入会员系统后，增加事件信息，处理充值升级会员信息

        // 返回
        return financialFlow.getFlowId();
    }

    private Long calculateBalanceAfter(FinancialFlowSaveReqVO createReqVO, Long previousBalance) {
        Long balanceAfter;
        if (AmountTypeEnum.RECHARGE.getValue().equals(createReqVO.getAmountType())) {
            // 充值：变动后余额 = 上一条记录的变动后余额 + 本次金额 + 满赠金额
            Long bonusAmount = createReqVO.getBonusAmount() != null ? createReqVO.getBonusAmount() : 0L;
            balanceAfter = previousBalance + createReqVO.getAmount() + bonusAmount;
        } else if (AmountTypeEnum.CONSUME.getValue().equals(createReqVO.getAmountType())) {
            // 消费：变动后余额 = 上一条记录的变动后余额 - 本次金额 * 折扣
            Long discountedAmount;
            if (createReqVO.getDiscount() != null && createReqVO.getDiscount().compareTo(BigDecimal.ZERO) > 0) {
                // 计算折扣后的金额
                discountedAmount = BigDecimal.valueOf(createReqVO.getAmount())
                        .multiply(createReqVO.getDiscount())
                        .longValue();
            } else {
                // 如果没有折扣，使用原始金额
                discountedAmount = createReqVO.getAmount();
            }
            balanceAfter = previousBalance - discountedAmount;

            // 防御性校验：余额不能为负数
            if (balanceAfter < 0) {
                throw exception(FINANCIAL_BALANCE_NOT_ENOUGH);
            }
        } else {
            // 未知交易类型，使用传入的余额
            balanceAfter = createReqVO.getBalanceAfter();
        }
        return balanceAfter;
    }

    private String createOrderNo(@NotNull(message = "用户ID（关联用户表）不能为空") Long userId, @NotEmpty(message = "金额类型（消费/充值）不能为空") String amountType) {
        return String.valueOf(userId + System.currentTimeMillis() + AmountTypeEnum.ofValue(amountType).getType());
    }

    @Override
    public void updateFinancialFlow(FinancialFlowSaveReqVO updateReqVO) {
        // 更新
        FinancialFlowDO updateObj = BeanUtils.toBean(updateReqVO, FinancialFlowDO.class);
        financialFlowMapper.updateById(updateObj);
    }

    @Override
    public void deleteFinancialFlow(Long id) {
        // 删除
        financialFlowMapper.deleteById(id);
    }

    @Override
        public void deleteFinancialFlowListByIds(List<Long> ids) {
        // 删除
        financialFlowMapper.deleteByIds(ids);
        }

    @Override
    public FinancialFlowDO getFinancialFlow(Long id) {
        return financialFlowMapper.selectById(id);
    }

    @Override
    public PageResult<FinancialFlowDO> getFinancialFlowPage(FinancialFlowPageReqVO pageReqVO) {
        return financialFlowMapper.selectPage(pageReqVO);
    }

    @Override
    public Map<Long, String> getUserBalanceMap(List<Long> userIds) {
        if (CollUtil.isEmpty(userIds)) {
            return Collections.emptyMap();
        }
        List<FinancialFlowDO> financialFlowList = financialFlowMapper.selectListByUserIds(userIds);
        if (CollUtil.isEmpty(financialFlowList)) {
            return Collections.emptyMap();
        }
        Map<Long, String> userBalanceMap = new HashMap<>();
        for (FinancialFlowDO financialFlow : financialFlowList) {
            userBalanceMap.put(financialFlow.getUserId(), MoneyUtils.fenToYuanStr(Math.toIntExact(financialFlow.getBalanceAfter())));
        }

        return userBalanceMap;
    }

    @Override
    public List<FinancialFlowDailyStatisticsRespVO> getDailyStatistics(Integer days, String amountType) {
        // 计算日期范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1); // 减去days-1天，确保包含今天

        // 查询数据库
        List<Map<String, Object>> resultList = financialFlowMapper.selectDailyStatistics(startDate, endDate, amountType);

        // 转换结果
        Map<LocalDate, Long> dateAmountMap = new HashMap<>();
        for (Map<String, Object> result : resultList) {
            LocalDate date = LocalDate.parse(result.get("date").toString());
            Long amount = Long.valueOf(result.get("amount").toString());
            dateAmountMap.put(date, amount);
        }

        // 填充所有日期，包括没有数据的日期
        List<FinancialFlowDailyStatisticsRespVO> statisticsList = new ArrayList<>();
        for (int i = 0; i < days; i++) {
            LocalDate date = startDate.plusDays(i);
            Long amount = dateAmountMap.getOrDefault(date, 0L);
            statisticsList.add(new FinancialFlowDailyStatisticsRespVO(date, amount));
        }

        return statisticsList;
    }

    @Override
    public List<FinancialFlowUserRankRespVO> getUserRank(Integer days, String amountType, Integer limit) {
        // 计算日期范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate = endDate.minusDays(days - 1); // 减去days-1天，确保包含今天

        // 查询数据库
        List<Map<String, Object>> resultList = financialFlowMapper.selectUserRank(startDate, endDate, amountType, limit);

        // 如果没有数据，返回空列表
        if (CollUtil.isEmpty(resultList)) {
            return Collections.emptyList();
        }

        // 获取所有用户ID
        List<Long> userIds = resultList.stream()
                .map(map -> Long.valueOf(map.get("user_id").toString()))
                .collect(Collectors.toList());

        // 获取用户名称
        Map<Long, String> userMap = javaInfoUserService.getUserMap(userIds);

        // 转换结果
        return resultList.stream().map(map -> {
            Long userId = Long.valueOf(map.get("user_id").toString());
            Long totalAmount = Long.valueOf(map.get("total_amount").toString());
            String userName = userMap.getOrDefault(userId, "未知用户");
            return new FinancialFlowUserRankRespVO(userId, userName, totalAmount);
        }).collect(Collectors.toList());
    }

    @Override
    public UserConsumptionStatsRespVO getUserConsumptionStats(Long userId) {
        // 1. 计算时间范围（近一年）
        LocalDateTime endTime = LocalDateTime.now();
        LocalDateTime startTime = endTime.minusYears(1);

        // 2. 查询用户消费统计数据
        List<Map<String, Object>> petStatsList = financialFlowMapper.selectUserPetConsumptionStats(
                userId, startTime, endTime, AmountTypeEnum.CONSUME.getValue());

        // 3. 如果没有数据，返回空统计
        if (CollUtil.isEmpty(petStatsList)) {
            UserConsumptionStatsRespVO emptyStats = new UserConsumptionStatsRespVO();
            emptyStats.setUserId(userId);
            emptyStats.setUserName(javaInfoUserService.getUser(userId).getUserName());
            emptyStats.setTotalAmount(0L);
            emptyStats.setPetStats(Collections.emptyList());
            return emptyStats;
        }

        // 4. 获取所有宠物ID
        List<Long> petIds = petStatsList.stream()
                .map(map -> Long.valueOf(map.get("pet_id").toString()))
                .collect(Collectors.toList());

        // 5. 获取宠物信息
        Map<Long, PetDO> petMap = new HashMap<>();
        for (Long petId : petIds) {
            PetDO pet = petService.getPet(petId);
            if (pet != null) {
                petMap.put(petId, pet);
            }
        }

        // 6. 计算总消费金额
        Long totalAmount = petStatsList.stream()
                .mapToLong(map -> Long.parseLong(map.get("amount").toString()))
                .sum();

        // 7. 构建响应对象
        UserConsumptionStatsRespVO respVO = new UserConsumptionStatsRespVO();
        respVO.setUserId(userId);
        respVO.setUserName(javaInfoUserService.getUser(userId).getUserName());
        respVO.setTotalAmount(totalAmount);

        // 8. 构建宠物消费统计列表
        List<UserConsumptionStatsRespVO.PetConsumptionStats> petStats = petStatsList.stream()
                .map(map -> {
                    Long petId = Long.valueOf(map.get("pet_id").toString());
                    Long amount = Long.valueOf(map.get("amount").toString());
                    Integer count = Integer.valueOf(map.get("count").toString());

                    PetDO pet = petMap.get(petId);
                    String petName = pet != null ? pet.getPetName() : "未知宠物";

                    return new UserConsumptionStatsRespVO.PetConsumptionStats(petId, petName, amount, count);
                })
                .collect(Collectors.toList());

        respVO.setPetStats(petStats);

        return respVO;
    }
}